package com.puzzlebazar.client.main.view;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.puzzlebazar.client.main.control.PuzzleTokenFactory;
import com.puzzlebazar.client.main.model.PuzzleList;
import com.puzzlebazar.client.puzzleinfo.PuzzleInfo;
import com.puzzlebazar.client.user.UserInfo;
import com.puzzlebazar.client.user.UserModel;
import com.puzzlebazar.client.util.Capabilities;
import com.puzzlebazar.client.util.ImageHyperlink;
import com.puzzlebazar.client.util.Observable;


/**
 * A composite that displays a list of puzzles that can be selected.
 */
public class PuzzleListView extends GenericListView implements UpdateTokenCallback {
	
	private static final String STYLE_PREFIX = "puzzle";
	private static final int NB_COLUMNS = 6;

	final PuzzleTokenFactory tokenFactory;

	protected final PuzzleList puzzleList;

	
	
	/**
	 * A composite widget responsible of displaying the list of all puzzles
	 * and from which the user can edit, play, create a new puzzle or delete
	 * existing puzzles.
	 *
	 * @param puzzleList The associated puzzle list model
	 * @param tokenFactory The factory to use to create the hyperlinks
	 */
	public PuzzleListView(PuzzleList puzzleList, PuzzleTokenFactory tokenFactory) {
		super( NB_COLUMNS );
		
		this.puzzleList = puzzleList;
		this.tokenFactory = tokenFactory;
				
		puzzleList.addObserver( this );		
	}

	/**
	 * Performs the deletion of a specific puzzle
	 * 
	 * @param puzzleIndex The index of the puzzle to delete
	 */
	private void deletePuzzle( int puzzleIndex ) {
		PuzzleInfo puzzleInfo = puzzleList.getPuzzle( puzzleIndex );
		if( !Window.confirm( "Really delete " + puzzleInfo.getGenre() + 
				" puzzle \"" + puzzleInfo.getTitle() + "\"? This action cannot be undone!" ) ) 
			return;
		
		puzzleList.deletePuzzle( puzzleIndex );
		puzzleList.notifyObservers();
	}

	@Override
	public void update(Observable observable, Object arg) {
		assert( observable == puzzleList );		
		updateView();		
	}

	@Override
	public void updateTokens() {
		updateView();
	}

	@Override
	public void release() {
		puzzleList.deleteObserver(this);
	}	

	@Override
	protected void refreshList() {
		puzzleList.refresh();
		puzzleList.notifyObservers();

	}

	@Override
	protected void addLineToTable(FlexTable table, int row, final int currentIndex) {		

		UserInfo userInfo = UserModel.get().getUserInfo();		
		final PuzzleInfo puzzleInfo = puzzleList.getPuzzle(currentIndex);
		final String puzzleInfoKey = puzzleInfo.getKey();
		final String startedHistoryInfoKey = puzzleInfo.getStartedByUserHistoryKey();
		HorizontalPanel buttons = new HorizontalPanel();

		if( puzzleInfo.isSolvedByUser() )
			table.setWidget( row, 0, new Image("Check.png") );
		
		// Add a new row to the table, then set each of its columns to the
		// puzzle's information
		if( Capabilities.canLoadPuzzle(userInfo,puzzleInfo) )
			buttons.add( new ImageHyperlink(new Image("ButtonInfo.png"), tokenFactory.getPuzzleInfoToken(puzzleInfoKey)) );
		else if( Capabilities.canLoadTutorial(userInfo,puzzleInfo) )
			buttons.add( new ImageHyperlink(new Image("ButtonInfo.png"), tokenFactory.getTutorialInfoToken(puzzleInfoKey)) );
		if( Capabilities.canContinuePuzzle(userInfo,puzzleInfo) )
			buttons.add( new ImageHyperlink( new Image("ButtonContinue.png"), tokenFactory.getContinueHistoryToken(startedHistoryInfoKey) ) );
		else if( Capabilities.canPlayPuzzle(userInfo,puzzleInfo) )
			buttons.add( new ImageHyperlink( new Image("ButtonPlay.png"), tokenFactory.getPlayPuzzleToken(puzzleInfoKey) ) );
		else if( Capabilities.canViewTutorial(userInfo,puzzleInfo) )
			buttons.add( new ImageHyperlink( new Image("ButtonPlay.png"), tokenFactory.getViewTutorialToken(puzzleInfoKey) ) );
		if( Capabilities.canEditPuzzle(userInfo,puzzleInfo)  )
			buttons.add( new ImageHyperlink( new Image("ButtonEdit.png"), tokenFactory.getEditPuzzleToken(puzzleInfoKey) ) );
		else if( Capabilities.canEditTutorial(userInfo,puzzleInfo)  )
			buttons.add( new ImageHyperlink( new Image("ButtonEdit.png"), tokenFactory.getEditTutorialToken(puzzleInfoKey) ) );
		
		if( Capabilities.canDeletePuzzleOrTutorial(userInfo,puzzleInfo) ) {
			Image buttonDelete = new Image("ButtonDelete.png");
			buttonDelete.addClickHandler( new ClickHandler(){
				@Override
				public void onClick(ClickEvent event) {
					deletePuzzle(currentIndex);
				}} );
			buttons.add(buttonDelete);
		}

		table.setWidget( row, 1, buttons );
		table.setHTML( row, 2, puzzleInfo.getGenreAndSize(true) );
		table.setHTML( row, 3, puzzleInfo.getDetails(true) );

		RatingDisplay difficultyRating = new RatingDisplay("bulb/bulb");
		difficultyRating.setRating( puzzleInfo.getDifficulty() );
		difficultyRating.setMax( PuzzleInfo.MAX_DIFFICULTY );
		difficultyRating.updateDisplay();			
		table.setWidget(row, 4, difficultyRating ); 

		RatingDisplay qualityRating = new RatingDisplay("star/star");
		qualityRating.setRating( puzzleInfo.getQuality() );
		qualityRating.setMax( PuzzleInfo.MAX_QUALITY );
		qualityRating.updateDisplay();			
		table.setWidget(row, 5, qualityRating ); 	
	}


	@Override
	protected boolean isRefreshing() {
		return puzzleList.isRefreshing();
	}
	
	@Override
	protected boolean isValid() {
		return puzzleList.isValid();
	}
	@Override
	protected int getListCount() {
		return puzzleList.getPuzzleCount();
	}

	@Override
	protected String getStylePrefix() {
		return STYLE_PREFIX;
	}

}
